package com.shop.util;

import java.sql.Connection;
import java.util.Properties;

import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.plugin.Intercepts;
import org.apache.ibatis.plugin.Invocation;
import org.apache.ibatis.plugin.Plugin;
import org.apache.ibatis.plugin.Signature;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.reflection.SystemMetaObject;
@Intercepts(value = { @Signature(args = { Connection.class,Integer.class}, method = "prepare", type = StatementHandler.class) })
public class QueryLimitPlugin implements Interceptor {
	private int limit;//默认限制查询返回行数
	private String dbType;
	//限制表中间别名，避免表重名所以起得怪些
	private static final String LMT_TABLE_NAME="limit_Table_Name_xxx";
	@Override
	public Object intercept(Invocation invocation) throws Throwable {
		//取出被拦截对象
		StatementHandler stmtHandler=(StatementHandler) invocation.getTarget();
		MetaObject metaStmtObject = SystemMetaObject.forObject(stmtHandler);
		//分离代理对象，从而形成多次代理，通过两次循环最原始的被代理类，MyBatis使用JDK代理
		while (metaStmtObject.hasGetter("h")) {
			Object object = metaStmtObject.getValue("h");
			metaStmtObject=SystemMetaObject.forObject(object);
		}
		//分离最后一个代理对象的目标类
		while (metaStmtObject.hasGetter("target")) {
			Object object=metaStmtObject.getValue("target");
			metaStmtObject=SystemMetaObject.forObject(object);
		}
		//取出执行的SQL
		String sql=(String)metaStmtObject.getValue("delegate.boundSql.sql");
		String limitSql;
		//判断参数是不是MySQL数据库且SQL有没有被插件重写过
		if ("mysql".equals(dbType) && sql.indexOf(LMT_TABLE_NAME) == -1) {
			sql=sql.trim();//去除前后空格
			//将参数写入SQL
			limitSql="select * from ("+sql+ ")" +LMT_TABLE_NAME+" limit "+limit;
			//重写要执行的sql
			System.out.println("修改后的sql:"+limitSql);
			metaStmtObject.setValue("delegate.boundSql.sql", limitSql);
		}
		//调用原来对象的方法，进入责任链的下一层级
		return invocation.proceed();
	}

	@Override
	public Object plugin(Object paramObject) {
		return Plugin.wrap(paramObject, this);
	}

	@Override
	public void setProperties(Properties props) {
		String strLimit=props.getProperty("limit", "2");
		this.limit=Integer.parseInt(strLimit);
		this.dbType=props.getProperty("dbType","mysql");
	}

}
